package com.itheima.webserver.service;

import cn.hutool.core.collection.CollUtil;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.commons.constants.IndexPojo;
import com.itheima.commons.model.domain.User;
import com.itheima.commons.model.domain.UserInfo;
import com.itheima.commons.model.vo.*;
import com.itheima.commons.utils.ToDateListUtil;
import com.itheima.dubbo.interfaces.UserApi;
import com.itheima.dubbo.interfaces.UserInfoApi;
import com.itheima.dubbo.interfaces.UserLoginDateApi;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/*
 * @ProjectName:project-exercise
 * @Package:com.itheima.webserver.service
 * @ClassName:DashboardService
 * @Author:ZHANG
 * @Date:2021-12-16 20:15
 * @Description:
 */
@Service
public class DashboardService {

    @Reference
    private UserApi userApi;

    @Reference
    private UserInfoApi userInfoApi;

    @Reference
    private UserLoginDateApi userLoginDateApi;


    /*
     * @MethodName:dashboardDistribution
     * @ParamType:[java.util.Date, java.util.Date]
     * @Param:[startDate, endDate]
     * @Exception:
     * @Return:DashboardVo
     * @Description:注册用户分布,行业top、年龄、性别、地区
     */
    public DashboardDistributionVo dashboardDistribution(String startDate, String endDate) {
        //查询出符合注册时间的用户
        List<UserInfo> userInfos = userInfoApi.queryUserByCreateDate(startDate, endDate);
        //获取这些用户的ids
        List<Long> userIds = CollUtil.getFieldValues(userInfos, "userId", Long.class);


        //获取所有的行业字段,并去重
        List<String> industryStrList = CollUtil.getFieldValues(userInfos, "industry", String.class).stream().distinct().collect(Collectors.toList());
        //求新注册的行业分布,分组查询数量,并排序,截取前十个
        List<IndustryDistributionVo> industryDistributionVoList = userInfoApi.queryNewUserIndustryCount(userIds, industryStrList);
        List<IndustryDistributionVo> industryDistributionVos= industryDistributionVoList.subList(0, 9);

        IndexPojo indexpojo = new IndexPojo();
        List<AgeDistributionVo> ageDistributionVos = new ArrayList<>();

        //求年龄分布,按照年龄区间查询
        for (UserInfo userInfo : userInfos) {
            if (userInfo.getAge() >= 0 && userInfo.getAge() <= 17) {
                indexpojo.underAge++;
            } else if (userInfo.getAge() >= 18 && userInfo.getAge() <= 23) {
                indexpojo.juvenile++;
            } else if (userInfo.getAge() >= 24 && userInfo.getAge() <= 30) {
                indexpojo.teenager++;
            } else if (userInfo.getAge() >= 31 && userInfo.getAge() <= 40) {
                indexpojo.youth++;
            } else if (userInfo.getAge() >= 41 && userInfo.getAge() <= 50) {
                indexpojo.middleAge++;
            } else if (userInfo.getAge() > 50) {
                indexpojo.agedness++;
            }
        }
        ageDistributionVos.add(AgeDistributionVo.builder().title("0-17岁").amount(indexpojo.underAge).build());
        ageDistributionVos.add(AgeDistributionVo.builder().title("18-23岁").amount(indexpojo.juvenile).build());
        ageDistributionVos.add(AgeDistributionVo.builder().title("24-30岁").amount(indexpojo.teenager).build());
        ageDistributionVos.add(AgeDistributionVo.builder().title("31-40岁").amount(indexpojo.youth).build());
        ageDistributionVos.add(AgeDistributionVo.builder().title("41-50岁").amount(indexpojo.middleAge).build());
        ageDistributionVos.add(AgeDistributionVo.builder().title("50岁+").amount(indexpojo.agedness).build());


        //性别分布,分组查询
        //获取性别字段集合并去重
        ArrayList<Integer> sexList = CollUtil.toList(1,2,3);
        List<GenderDistributionVo> genderDistributionVos = userInfoApi.queryNewUserGenderCount(sexList, userIds);


        //模糊查询省份,查询数量
        List<String> provinceList = CollUtil.toList("上海", "河北", "山西", "内蒙古", "辽宁", "吉林", "黑龙江", "江苏", "浙江", "安徽", "福建", "江西", "山东",
                "河南", "湖北", "湖南", "广东", "广西", "海南", "四川", "贵州", "云南", "西藏", "陕西", "甘肃", "青海", "宁夏", "新疆", "北京",
                "天津", "重庆", "香港", "澳门", "台湾");
        List<LocalDistributionVo> localDistributionVos = userInfoApi.queryNewUserProvinceCount(provinceList, userIds);


        //按照地区合计,数量
        //华南  广东,广西,海南,福建,香港,澳门,台湾
        List<LocalTotalVo> localTotalVos = new ArrayList<>();
        String huaNan = "华南地区";
        List<String> huaNanList = CollUtil.toList("广东", "广西", "海南", "福建", "香港", "澳门", "台湾");
        LocalTotalVo huaNanTotalVo = userInfoApi.queryNewUserArea(huaNan, huaNanList, userIds);
        localTotalVos.add(huaNanTotalVo);
        //华北 北京,天津,河北,山西,内蒙古
        String huaBei = "华北地区";
        List<String> huaBeiList = CollUtil.toList("北京", "天津", "河北", "山西", "内蒙古");
        LocalTotalVo huaBeiTotalVo = userInfoApi.queryNewUserArea(huaBei, huaBeiList, userIds);
        localTotalVos.add(huaBeiTotalVo);
        //西北 陕西,甘肃,新疆,青海,宁夏
        String xiBei = "西北地区";
        List<String> xiBeiList = CollUtil.toList("陕西", "甘肃", "新疆", "青海", "宁夏");
        LocalTotalVo xiBeiTotalVo = userInfoApi.queryNewUserArea(xiBei, xiBeiList, userIds);
        localTotalVos.add(xiBeiTotalVo);
        //华东 上海,江苏,浙江,山东,安徽
        String huaDong = "华东地区";
        List<String> huaDongList = CollUtil.toList("上海", "江苏", "浙江", "山东", "安徽");
        LocalTotalVo huaDongTotalVo = userInfoApi.queryNewUserArea(huaDong, huaDongList, userIds);
        localTotalVos.add(huaDongTotalVo);
        //东北 辽宁,吉林,黑龙江
        String dongBei = "东北地区";
        List<String> dongBeiList = CollUtil.toList("辽宁", "吉林", "黑龙江");
        LocalTotalVo dongBeiTotalVo = userInfoApi.queryNewUserArea(dongBei, dongBeiList, userIds);
        localTotalVos.add(dongBeiTotalVo);
        //华中 湖北,湖南,河南,江西
        String huaZhong = "华中地区";
        List<String> huaZhongList = CollUtil.toList("湖北", "湖南", "河南", "江西");
        LocalTotalVo huaZhongTotalVo = userInfoApi.queryNewUserArea(huaZhong, huaZhongList, userIds);
        localTotalVos.add(huaZhongTotalVo);
        //西南 四川,重庆,贵州,云南,西藏
        String xiNan = "西南地区";
        List<String> xiNanList = CollUtil.toList("四川", "重庆", "贵州", "云南", "西藏");
        LocalTotalVo xiNanTotalVo = userInfoApi.queryNewUserArea(xiNan, xiNanList, userIds);
        localTotalVos.add(xiNanTotalVo);


        //拼接vo对象
        DashboardDistributionVo dashboardDistributionVo = new DashboardDistributionVo();
        dashboardDistributionVo.setIndustryDistribution(industryDistributionVos);
        dashboardDistributionVo.setAgeDistribution(ageDistributionVos);
        dashboardDistributionVo.setGenderDistribution(genderDistributionVos);
        dashboardDistributionVo.setLocalDistribution(localDistributionVos);
        dashboardDistributionVo.setLocalTotal(localTotalVos);

        return dashboardDistributionVo;
    }

    /*
     * @MethodName:queryUsersAddActiveRetentionRate
     * @ParamType:[java.util.Date, java.util.Date, java.lang.String]
     * @Param:[startDate, endDate, type]
     * @Exception:
     * @Return:DashboardUsersVo
     * @Description:新增、活跃用户、次日留存率
     */
    public DashboardUsersVo queryUsersAddActiveRetentionRate(String startDate, String endDate, String type) {
        //判断时间是否符合规范
        //计算去年的时间

        DashboardUsersVo dashboardUsersVo = new DashboardUsersVo();
        switch (type) {
            //新增用户某段时间内
            case "101": {
                dashboardUsersVo = findAddUserBrokenLine(startDate, endDate);
                return dashboardUsersVo;
            }
            //活跃用户,去重
            case "102": {
                dashboardUsersVo = findActiveUserBrokenLine(startDate, endDate);
                return dashboardUsersVo;

            }
            //次日留存率
            case "103": {
                dashboardUsersVo = findRetentionRateBrokenLine(startDate, endDate);
                return dashboardUsersVo;

            }
        }
        return dashboardUsersVo;
    }

    //求次日留存率
    private DashboardUsersVo findRetentionRateBrokenLine(String startDate, String endDate) {
        //获取时间的集合
        //今年的集合
        List<String> thisYearDateList = ToDateListUtil.getDateList(startDate, endDate);
        List<ReturnDataVo> thisYearReturnDataVos = userInfoApi.queryPeriodRetentionRate(thisYearDateList);
        //去年的集合
        Date lastYearStartDate = DateUtil.offset(Convert.toDate(startDate), DateField.YEAR, -1);
        Date lastYearEndDate = DateUtil.offset(Convert.toDate(endDate), DateField.YEAR, -1);
        List<String> lastYearDateList = ToDateListUtil.getDateList(DateUtil.formatTime(lastYearStartDate), DateUtil.formatTime(lastYearEndDate));
        List<ReturnDataVo> lastYearReturnDataVos = userInfoApi.queryPeriodRetentionRate(lastYearDateList);
        return new DashboardUsersVo(thisYearReturnDataVos, lastYearReturnDataVos);
    }

    //某段时间的活跃用户
    private DashboardUsersVo findActiveUserBrokenLine(String startDate, String endDate) {
        //今年
        List<String> thisYearDateList = ToDateListUtil.getDateList(startDate, endDate);
        List<ReturnDataVo> thisYearReturnDataVo = userInfoApi.queryPeriodActiveUserCount(thisYearDateList);
        //去年
        //获取去年的日期
        Date lastYearStartDate = DateUtil.offset(Convert.toDate(startDate), DateField.YEAR, -1);
        Date lastYearEndDate = DateUtil.offset(Convert.toDate(endDate), DateField.YEAR, -1);
        List<String> lastYearDateList = ToDateListUtil.getDateList(DateUtil.formatTime(lastYearStartDate), DateUtil.formatTime(lastYearEndDate));
        List<ReturnDataVo> lastYearReturnDataVo = userInfoApi.queryPeriodActiveUserCount(lastYearDateList);

        return new DashboardUsersVo(thisYearReturnDataVo, lastYearReturnDataVo);
    }

    //新增用户某段时间内
    private DashboardUsersVo findAddUserBrokenLine(String startDate, String endDate) {
        //今年
        List<String> thisYearDateList = ToDateListUtil.getDateList(startDate, endDate);
        List<ReturnDataVo> thisYearReturnDataVo = userInfoApi.queryPeriodNewUserCount(thisYearDateList);
        //去年
        //获取去年的日期
        Date lastYearStartDate = DateUtil.offset(Convert.toDate(startDate), DateField.YEAR, -1);
        Date lastYearEndDate = DateUtil.offset(Convert.toDate(endDate), DateField.YEAR, -1);
        List<String> lastYearDateList = ToDateListUtil.getDateList(DateUtil.formatTime(lastYearStartDate), DateUtil.formatTime(lastYearEndDate));
        List<ReturnDataVo> lastYearReturnDataVo = userInfoApi.queryPeriodNewUserCount(lastYearDateList);

        return new DashboardUsersVo(thisYearReturnDataVo, lastYearReturnDataVo);
    }


    /*
     * @MethodName:queryOverviewStatistics
     * @ParamType:[]
     * @Param:[]
     * @Exception:
     * @Return:DashboardSummaryVo
     * @Description:概要统计信息
     */
    public DashboardSummaryVo queryOverviewStatistics() {
        //查询累计用户
        List<User> userList = userApi.queryUserList();
        String allUserCountStr = Convert.toStr(userList.size());
        //查询过去七天活跃用户
        //当前日期字符串，格式：yyyy-MM-dd,格式为Date
        Date date = new Date();
        String week = "7";
        Long weekCount = queryActiveUserByPastPeriod(week, date);
        //查询过去30天活跃用户
        String month = "30";
        Long monthCount = queryActiveUserByPastPeriod(month, date);
        //过去七天平均使用时长(不写)

        //新增用户今日与环比
        //今日新增用户
        Long todayCount = queryOneDayNewUser(date);
        //昨日新增用户

        Date yesterday = decreaseOneDay(date);

        Long yesterdayCount = queryOneDayNewUser(yesterday);

        //计算环比
        String newUsersTodayRateStr = Convert.toStr((todayCount - yesterdayCount) / yesterdayCount);


        //登录次数今日与环比
        //今日登录次数
        Long todayLoginTimesCount = queryOneDayLoginUserTimes(date);
        //昨日登录次数

        Long yesterdayLoginTimesCount = queryOneDayLoginUserTimes(yesterday);

        //计算环比

        String loginTimesTodayRate = Convert.toStr((todayLoginTimesCount - yesterdayLoginTimesCount) / yesterdayLoginTimesCount);

        //活跃用户今日与环比
        //今日
        Long todayActiveUserCount = queryOneDayActiveUser(date);

        //昨日

        Long yesterdayActiveUserCount = queryOneDayActiveUser(yesterday);

        //计算环比
        String activeUsersTodayRateStr = Convert.toStr((todayActiveUserCount - yesterdayActiveUserCount) / yesterdayActiveUserCount);

        //活跃用户昨日与环比
        //前天的活跃用户
        //日期减二
        Date preYesterday = DateUtil.offsetDay(date, -2);
        Long preYesterdayActiveUserCount = queryOneDayActiveUser(preYesterday);

        //求环比
        String activeUsersYesterdayRateStr = Convert.toStr((yesterdayActiveUserCount - preYesterdayActiveUserCount) / preYesterdayActiveUserCount);

        //拼接vo对象
        DashboardSummaryVo dashboardSummaryVo = new DashboardSummaryVo();
        dashboardSummaryVo.setCumulativeUsers(allUserCountStr);
        dashboardSummaryVo.setActivePassMonth(Convert.toStr(monthCount));
        dashboardSummaryVo.setActivePassWeek(Convert.toStr(weekCount));
        dashboardSummaryVo.setNewUsersToday(Convert.toStr(todayCount));
        dashboardSummaryVo.setNewUsersTodayRate(newUsersTodayRateStr);
        dashboardSummaryVo.setLoginTimesToday(Convert.toStr(todayLoginTimesCount));
        dashboardSummaryVo.setLoginTimesTodayRate(loginTimesTodayRate);
        dashboardSummaryVo.setActiveUsersToday(Convert.toStr(todayActiveUserCount));
        dashboardSummaryVo.setActiveUsersTodayRate(activeUsersTodayRateStr);
        dashboardSummaryVo.setUseTimePassWeek(" ");
        dashboardSummaryVo.setActiveUsersYesterday(Convert.toStr(yesterdayActiveUserCount));
        dashboardSummaryVo.setActiveUsersYesterdayRate(activeUsersYesterdayRateStr);

        return dashboardSummaryVo;
    }

    private Long queryOneDayActiveUser(Date date) {
        return userInfoApi.queryOneDayActiveUser(date);
    }

    //查询某天的登录次数
    private Long queryOneDayLoginUserTimes(Date date) {
        return userLoginDateApi.queryOneDayLoginUser(date);
    }

    //查询某天的注册用户数
    private Long queryOneDayNewUser(Date date) {
        return userApi.queryOneDayNewUser(date);
    }

    //日期减一
    private Date decreaseOneDay(Date date) {
        Date offsetDay = DateUtil.offsetDay(date, -1);
        return offsetDay;
    }

    //查询一段时间里活跃用户数
    private Long queryActiveUserByPastPeriod(String days, Date date) {
        return userLoginDateApi.queryActiveUserByPastPeriod(days, date);
    }



}
